﻿using System;
using System.Collections.Generic;
using JSH.ITDiplom.OOPC01.PersonalIdentityNumber.BusinessLayer;
using JSH.ITDiplom.OOPC01.PersonalIdentityNumber.BusinessLayer.da;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace JSH.ITDiplom.OOPC01.PersonalIdentityNumber.UnitTest
{
    /// <summary>
    /// Test class DanishPersonalIdentityNumber 
    /// </summary>
    [TestClass]
    public class TestDanish
    {
        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        /// <summary>
        /// Lowest date that can be accepted as a danish personal number
        /// </summary>
        [TestMethod]
        public void Test18580101()
        {
            var danish = new DanishPersonalIdentityNumber("0101588653");
            
            IList<string> errors;
            bool ok = danish.Validate(out errors);
            if (!ok) {
                Util.LogErrors(errors);
                Assert.Fail("Should not fail");
            }
            Assert.AreEqual(new DateTime(1858, 1, 1), danish.BirthDay,
                "Wrong birthday");
            Assert.AreEqual(Gender.Male, danish.Gender, "Wrong gender");
            
        }

        /// <summary>
        /// Highest date that can be accepted as a danish personal number
        /// </summary>
        [TestMethod]
        public void Test20571231()
        {
            var danish = new DanishPersonalIdentityNumber("3112578659");

            IList<string> errors;
            bool ok = danish.Validate(out errors);
            if (!ok)
            {
                Util.LogErrors(errors);
                Assert.Fail("Should not fail");
            }
            Assert.AreEqual(new DateTime(2057, 12, 31), danish.BirthDay,
                "Wrong birthday");
            Assert.AreEqual(Gender.Male, danish.Gender, "Wrong gender");
        }

        /// <summary>
        /// Test a number with date 31 feb. 2009
        /// </summary>
        [TestMethod]
        public void Test20090231()
        {
            var danish = new DanishPersonalIdentityNumber("3102094203");

            IList<string> errors;
            bool ok = danish.Validate(out errors);
            if (ok)
            {
                Assert.Fail("Should fail");
            }
            else
            {
                Util.LogErrors(errors);
                Assert.AreEqual(2, errors.Count, "2 error expected");
                Assert.AreEqual(
                    "JSH.ITDiplom.OOPC01.PersonalIdentityNumber.BusinessLayer.DateValidation", 
                    errors[0], "Wrong error");
                Assert.AreEqual(
                    "JSH.ITDiplom.OOPC01.PersonalIdentityNumber.BusinessLayer.da.Modulus11Validation",
                     errors[1], "Wrong error");
                Assert.AreEqual(null, danish.BirthDay, "Wrong birthday");
                Assert.AreEqual(Gender.Male, danish.Gender, "Wrong gender");
            }
        }

        /// <summary>
        /// Test a personal number with a "+" instead of a "-"
        /// </summary>
        [TestMethod]
        public void TestWrongFormat()
        {
            var danish = new DanishPersonalIdentityNumber("010488+4679");

            IList<string> errors;
            bool ok = danish.Validate(out errors);
            Util.LogErrors(errors);
            if (ok)
            {
                Assert.Fail("Should fail");
            }
            else
            {
                Assert.AreEqual(1, errors.Count, "Only one error expected");
                Assert.AreEqual(
                    "JSH.ITDiplom.OOPC01.PersonalIdentityNumber.BusinessLayer.da.FormatValidation",
                    errors[0], "Wrong error");
            }
        }

        /// <summary>
        /// Test a personal number with a modulus 11 error
        /// </summary>
        [TestMethod]
        public void TestModulus11Error()
        {
            var danish = new DanishPersonalIdentityNumber("010488-4672");

            IList<string> errors;
            bool ok = danish.Validate(out errors);
            Util.LogErrors(errors);
            if (ok)
            {
                Assert.Fail("Should fail");
            }
            else
            {
                Assert.AreEqual(1, errors.Count, "Only one error expected");
                Assert.AreEqual(
                    "JSH.ITDiplom.OOPC01.PersonalIdentityNumber.BusinessLayer.da.Modulus11Validation", 
                    errors[0], "Wrong error");
            }
        }

        /// <summary>
        /// Test a personal number with birthday 1/1-1965 and male and modulus11 error.
        /// </summary>
        [TestMethod]
        public void TestBirthDayAndGenderWithNoModulus11()
        {
            //0101653579 if modulus11 is right
            var danish = new DanishPersonalIdentityNumber("0101653571");

            IList<string> errors;
            bool ok = danish.Validate(out errors);
            Util.LogErrors(errors);
            if (!ok)
            {
                Assert.Fail("Should not fail");
            }
        }

        /// <summary>
        /// Test generate with birthday 1/1-2001 and Male.
        /// </summary>
        [TestMethod]
        public void TestGenerate20010101Male()
        {
            DateTime birthday = new DateTime(2001, 1, 1);
            const Gender sex = Gender.Male;
            IList<string> personalNumbers = 
                DanishPersonalIdentityNumber.Generate(birthday,
                sex);
            Console.WriteLine("Number of personal numbers=" + personalNumbers.Count);
            int i = 0;
            foreach (string s in personalNumbers)
            {
                i++;
                Console.WriteLine("" + i + " - " + s);
                var danish = new DanishPersonalIdentityNumber(s);
                Assert.IsTrue(danish.Validate(), "Error");
                Assert.AreEqual(birthday, danish.BirthDay, "Wrong birthday");
                Assert.AreEqual(sex, danish.Gender, "Wrong gender");
            }
        }

        /// <summary>
        /// Test generate with birthday 1/1-2001 and Female.
        /// </summary>
        [TestMethod]
        public void TestGenerate20010101Female()
        {
            DateTime birthday = new DateTime(2001, 1, 1);
            const Gender sex = Gender.Female;
            IList<string> personalNumbers =
                DanishPersonalIdentityNumber.Generate(birthday,
                sex);
            Console.WriteLine("Number of personal numbers=" + personalNumbers.Count);
            int i = 0;
            foreach (string s in personalNumbers)
            {
                i++;
                Console.WriteLine("" + i + " - " + s);
                var danish = new DanishPersonalIdentityNumber(s);
                Assert.IsTrue(danish.Validate(), "Error");
                Assert.AreEqual(birthday, danish.BirthDay, "Wrong birthday");
                Assert.AreEqual(sex, danish.Gender, "Wrong gender");
            }
        }

        /// <summary>
        /// Test "Birthday out of range" exception.
        /// </summary>
        [TestMethod]
        public void TestGenerateException()
        {
            try
            {
                DanishPersonalIdentityNumber.Generate(new DateTime(2101, 1, 1),
                    Gender.Female);
                Assert.Fail("Should throw an exception");
            }
            catch (ArgumentException ae)
            {
                Assert.AreEqual("Birthdate out of date range", ae.Message,
                    "Wrong exception message");
            }
        }
    }
}